﻿using System;
using System.IO;
using System.Threading;
using LoungeRepo.Contracts.EntityStore;

namespace LoungeRepo.EntityStore
{
    partial class FilesystemEntityStore
    {
        private Stream CreateEntityFile(IStreamedEntity streamedEntity)
        {
            var entityFilename = CreateEntityFilename(streamedEntity.Id, streamedEntity.Partition);
            CreateDirectory(Path.GetDirectoryName(entityFilename));
            return RetryConnectToFile(() =>
                new FileStream(entityFilename, FileMode.Create, FileAccess.Write, FileShare.None)
                );
        }


        private Stream OpenEntityFile(string id, string partition)
        {
            return RetryConnectToFile(() => 
                new FileStream(CreateEntityFilename(id, partition), 
                               FileMode.Open, FileAccess.Read, FileShare.Read)
                );
        }


        private Stream RetryConnectToFile(Func<Stream> connectFunction)
        {
            const int DELAY_BETWEEN_TRIALS_MSEC = 100;
            const int MAX_TRIALS = 5;
            int iTrial = 0;
            while (true)
            {
                iTrial++;
                try
                {
                    return connectFunction();
                }
                catch
                {
                    if (iTrial > MAX_TRIALS) throw;
                    Thread.Sleep(DELAY_BETWEEN_TRIALS_MSEC);
                }
            }
        }


        private string CreateEntityFilename(string id, string partition)
        {
            return string.Format(@"{0}\{1}\{2}.entity", this.rootFolder, partition, id);
        }


        private void CreateDirectory(string dirPath)
        {
            if (!Directory.Exists(dirPath))
                Directory.CreateDirectory(dirPath);
        }
    }
}
